package ftx

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"

	"github.com/astaxie/beego/logs"
)

/**
 * MQ的回调处理
 * 消费MQ的数据
 * 将消费的数据转换成最终的数据
 * 最终的数据写入缓存
**/
var DepthConsumerHandle = func(symbol, origin string, dataByte []byte, depth *CacheDepth) (data string) {

	newDepth := new(CacheDepth)
	err := jsonIteratorr.Unmarshal(dataByte, newDepth)
	if err != nil {
		fmt.Println("ftx [DepthConsumerHandle] err ", err)
	}

	if len(depth.Asks)*len(depth.Bids) == 0 {
		err = jsonIteratorr.Unmarshal(dataByte, depth)
		if err != nil {
			fmt.Println("ftx [DepthConsumerHandle] err ", err)
		}

	} else if !reflect.DeepEqual(depth, &CacheDepth{}) {
		depth.Mu.Lock()
		diffDepth(depth, newDepth)
		depth.Mu.Unlock()

		if !depth.CheckCRC32() {
			// TODO 重新订阅
			return ""
		}
	} else {
		return
	}

	if len(depth.Bids)*len(depth.Asks) <= 0 {
		return
	}

	data, err = jsonIteratorr.MarshalToString(depth)
	if err != nil {
		logs.Debug("[ftx-DepthConsumerHandle] ", err)
		return
	}
	// data = *(*string)(unsafe.Pointer(&datab))
	return
}

// 处理ticker
var TickerConsumerHandle = func(message []byte) (data string) {
	data = string(message)
	return
}

// 处理trade
var TradeConsumerHandle = func(message []byte) (data string) {
	data = string(message)
	return
}

/**
 * 自定义处理行情数据的解析
 * 每个行情对应一个独立的解析方式
**/
// Quant-Handle
var DepthHandle = func(message []byte, origin string) (data []byte, err error) {

	depth := &Depth{}

	if err = json.Unmarshal(message, depth); err != nil {
		logs.Debug("[exchange-ftx-handle] ", err, string(message))
		return
	}

	//
	depth.MarketAssign(origin)
	if !depth.IsValid() {
		err = errors.New("[ftx-DepthHandle] err ")
		return
	}

	data, err = json.Marshal(depth)
	return
}

// Trade-Handle
var TradeHandle = func(message []byte, origin string) (data []byte, err error) {

	trade := &Quotation{}

	if err = json.Unmarshal(message, trade); err != nil {
		logs.Debug("[exchange-ftx-handle] ", err, string(message))
		return
	}

	//
	trade.MarketAssign(origin)
	if !trade.IsValid() {
		err = errors.New("[ftx-TradeHandle] err ")
		return
	}

	data, err = json.Marshal(trade)
	return
}

// Ticker-Handle
var TickerHandle = func(message []byte, origin string) (data []byte, err error) {

	ticker := &Ticker{}

	if err = json.Unmarshal(message, ticker); err != nil {
		logs.Debug("[ftx-TickerHanlde]", err, string(message))
		return
	}

	ticker.MarketAssign(origin)
	if !ticker.IsValid() {
		err = errors.New("[ftx-TickerHanlde] err ")
		return
	}

	// 序列化格式
	data, err = json.Marshal(ticker)
	return
}

// depth --> bids
func BidsFormat(data []Bid) []map[string]interface{} {
	if len(data) <= 0 {
		return []map[string]interface{}{}
	}

	bidsMap := make([]map[string]interface{}, len(data))
	for index, value := range data {
		bidsMap[index] = map[string]interface{}{
			"price":  value[0],
			"amount": value[1],
			"type":   1,
		}
	}

	// MarshalError := e.NewMarshalError(json.Marshal(bidsMap))
	// res := MarshalError.Result_Unwrap()
	return bidsMap
}

// depth --> asks
func AsksFormat(data []Ask) []map[string]interface{} {

	if len(data) <= 0 {
		return []map[string]interface{}{}
	}

	asksMap := make([]map[string]interface{}, len(data))
	for index, value := range data {
		asksMap[index] = map[string]interface{}{
			"price":  value[0],
			"amount": value[1],
			"type":   0,
		}
	}

	// MarshalError := e.NewMarshalError(json.Marshal(asksMap))
	// res := MarshalError.Result_Unwrap()
	return asksMap

}

/**
	对depth 最新旧数据对比，并且更新旧的数据，以保证数据同步
**/
func diffDepth(oldDepth, newDepth *CacheDepth) {

	/**
	 * 判断u <= 快照中的lastUpdateId  过滤掉
	 * 如果 U
	**/
	// 数据存在的话
	// if oldDepth.Time > newDepth.Time {
	// 	// 不处理时间回流
	// 	return
	// }

	oldDepth.Time = newDepth.Time
	oldDepth.CheckSum = newDepth.CheckSum

	// TODO 关于丢包导致的该撤单的没有撤单，该成交的没有成交的订单，需要定期获取全量数据来做过滤
	// TODO 关于盘口的处理问题, 如果双向出现交集需要处理

	// 循环遍历对比两个数据差异
	isBidEquel := false

	for i := 0; i < len(newDepth.Bids); i++ {
		// 如果有的 amount ==0 的则删除
		// 如果有且 amount >0 则更新d.Bids[i].Amount
		amount := newDepth.Bids[i].Amount

		for j := 0; j < len(oldDepth.Bids); j++ {

			if oldDepth.Bids[j].Price == newDepth.Bids[i].Price {
				isBidEquel = true
				// 新数据的数量是否有变化
				if newDepth.Bids[i].Amount >= 0.0 {
					// 更新
					// oldDepth.Bids[j].Amount = newDepth.Bids[i].Amount
					oldDepth.UpdateBidsAmount(j, newDepth.Bids[i].Amount)
				}

				if amount == 0 {
					// 移除
					if len(oldDepth.Bids) > 1 {
						// oldDepth.Bids = append(oldDepth.Bids[:j], oldDepth.Bids[j+1:]...)
						oldDepth.AppendBidsSlice(j, oldDepth.Bids[j+1:]...)
					} else {
						oldDepth.Bids = []OrderBook{}
					}
				}

			}

		}

		// 增加新的订单累计
		if !isBidEquel && amount != 0 {
			oldDepth.AppendBids(newDepth.Bids[i])
		}
		isBidEquel = false

	}

	isAsksEquel := false
	for i := 0; i < len(newDepth.Asks); i++ {
		// 如果有的 amount ==0 的则删除
		// 如果有且 amount >0 则更新
		amount := newDepth.Asks[i].Amount

		for j := 0; j < len(oldDepth.Asks); j++ {

			if oldDepth.Asks[j].Price == newDepth.Asks[i].Price {
				isAsksEquel = true
				// 新数据的数量是否有变化
				if newDepth.Asks[i].Amount >= 0.0 {
					// 更新
					// oldDepth.Asks[j].Amount = newDepth.Asks[i].Amount
					oldDepth.UpdateAsksAmount(j, newDepth.Asks[i].Amount)
				}

				if amount == 0 {
					// 移除
					if len(oldDepth.Asks) > 1 {
						// oldDepth.Asks = append(oldDepth.Asks[:j], oldDepth.Asks[j+1:]...)
						oldDepth.AppendAsksSlice(j, oldDepth.Asks[j+1:]...)
					} else {
						oldDepth.Asks = []OrderBook{}
					}
				}
			}

		}

		// 增加新的订单累计
		if !isAsksEquel && amount != 0 {
			// oldDepth.Asks = append(oldDepth.Asks, newDepth.Asks[i])
			oldDepth.AppendAsks(newDepth.Asks[i])
		}
		isAsksEquel = false
	}

	// 切割diffDepth
	oldDepth.Asks = CutSlice(InsertSort(oldDepth.Asks))
	oldDepth.Bids = CutSlice(InsertReseverSort(oldDepth.Bids))
}

func MergeSort(intList []OrderBook, desc string) []OrderBook {
	length := len(intList)

	// 长度为0直接退出
	if length <= 1 {
		return intList
	}

	// 先分
	middle := length / 2
	left := MergeSort(intList[:middle], desc)
	right := MergeSort(intList[middle:], desc)

	// 后治
	if desc == "sort" {
		return sortMerge(left, right)
	} else {
		return reseverMerge(left, right)
	}
}

func reseverMerge(left, right []OrderBook) []OrderBook {

	leftLen := len(left)
	rightLen := len(right)
	// 定义i,j指针指向left,right的,开始
	i, j, count := 0, 0, 0
	// 定义临时切片
	temp := make([]OrderBook, len(left)+len(right))
	for i < leftLen && j < rightLen {
		leftPrice := left[i].Price
		rightPrice := right[j].Price
		if leftPrice > rightPrice {
			// 将左边的值放入temp
			temp[count] = left[i]
			i++
		} else {
			// 将右边的值放入temp
			// temp = append(temp, right[j])
			temp[count] = right[j]
			j++
		}
		count++
	}
	// 结束循环后会多有一个切片有余
	if i < leftLen {
		// 如果左边有余
		for i < leftLen {
			temp[count] = left[i]
			count++
			i++
		}

		// temp = append(temp, left[i:]...)
	} else if j < rightLen {
		// 如果右边有余
		for j < rightLen {
			temp[count] = right[j]
			count++
			j++
		}
		// temp = append(temp, right[j:]...)
	}
	return temp
}

func sortMerge(left, right []OrderBook) []OrderBook {
	leftLen := len(left)
	rightLen := len(right)
	// 定义i,j指针指向left,right的,开始
	i, j, count := 0, 0, 0
	// 定义临时切片
	// temp := make([]OrderBook, 0)
	temp := make([]OrderBook, len(left)+len(right))

	for i < leftLen && j < rightLen {
		leftPrice := left[i].Price
		rightPrice := right[j].Price
		if leftPrice < rightPrice {
			// 将左边的值放入temp
			// temp = append(temp, left[i])
			temp[count] = left[i]
			i++
		} else {
			// 将右边的值放入temp
			// temp = append(temp, right[j])
			temp[count] = right[j]
			j++
		}
		count++
	}
	// 结束循环后会多有一个切片有余
	if i < leftLen {
		// 如果左边有余
		for i < leftLen {
			temp[count] = left[i]
			count++
			i++
		}

		// temp = append(temp, left[i:]...)
	} else if j < rightLen {
		// 如果右边有余
		for j < rightLen {
			temp[count] = right[j]
			count++
			j++
		}
		// temp = append(temp, right[j:]...)
	}
	return temp
}

func toBytes(data string) *Depth {
	depth := new(Depth)
	_ = json.Unmarshal([]byte(data), &depth)
	return depth
}

func CutSlice(books []OrderBook) []OrderBook {
	num := 1000
	if len(books) > num {
		return books[:num]
	} else {
		return books
	}
}

// 选择排序
func InsertSort(arr []OrderBook) []OrderBook {
	n := len(arr)
	for i := 0; i < n-1; i++ {

		leftPrice := arr[i+1].Price
		rightPrice := arr[i].Price
		if leftPrice < rightPrice {

			for j := i + 1; j > 0; j-- {
				arrleftPrice := arr[j].Price
				arrrightPrice := arr[j-1].Price
				if arrleftPrice < arrrightPrice {
					arr[j], arr[j-1] = arr[j-1], arr[j]
				}
			}
		}
	}
	return arr
}

func InsertReseverSort(arr []OrderBook) []OrderBook {
	n := len(arr)
	for i := 0; i < n-1; i++ {
		leftPrice := arr[i+1].Price
		rightPrice := arr[i].Price
		if leftPrice > rightPrice {
			for j := i + 1; j > 0; j-- {
				arrleftPrice := arr[j].Price
				arrrightPrice := arr[j-1].Price
				if arrleftPrice > arrrightPrice {
					arr[j], arr[j-1] = arr[j-1], arr[j]
				}
			}
		}
	}
	return arr
}
